package org.flowable.flowablespringb3;

import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;

import java.util.*;

@SpringBootTest
class FlowableTests02 {
    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private TaskService taskService;

    @Test
    void contextLoads() {
        System.out.println("processEngine: "+ processEngine);
        System.out.println("runtimeService: "+ runtimeService);
        System.out.println("repositoryService: "+ repositoryService);
        System.out.println("taskService: "+ taskService);
    }

    // 1. 部署流程
    // 部署完成后在 ACT_RE_DEPLOYMENT 表会见到一条 name=demoFlow2 的数据
    // 在 ACT_RE_PROCDEF 表中其 ACT_RE_PROCDEF.key = "processes/demoFlow2.bpmn20.xml" -> process.id
    @Test
    void deploy() {
        Deployment deployment = repositoryService
                // 创建一个部署
                .createDeployment()
                //部署的流程图, 可以一次添加多个流程图
                .addClasspathResource("processes/demoFlow2.bpmn20.xml")
                //这次部署的名字
                .name("demoFlow2")
                .deploy();
        // deployment: DeploymentEntity[id=d778e129-cf3e-11ef-8c0e-aae291037f7a, name=demoFlow1]
        System.out.println("deployment: "+ deployment);
    }

    // 通过 deploy() 方法返回的 deployment.id 查询 当此流程部署定义的id 或者 key
    // 例如返回内容为  deployment: DeploymentEntity[id=d778e129-cf3e-11ef-8c0e-aae291037f7a, name=demoFlow1]
    // 则下述 getProcessDefinition 方法 内 .deploymentId("d778e129-cf3e-11ef-8c0e-aae291037f7a")
    @Test
    void getProcessDefinition() {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId("959f2258-cf67-11ef-a431-4c496c811f92")
                .latestVersion() // 获取最新版本
                .singleResult();

        System.out.println("pd.getDeploymentId() = " + processDefinition.getDeploymentId());
        System.out.println("pd.getId() = " + processDefinition.getId());
        System.out.println("pd.getKey() = " + processDefinition.getKey());
    }

    // 可以根据  processDefinition.getId() | processDefinition.getKey() 来启动一个流程
    // 例如上述 getProcessDefinition 方法返回的内容为
    // pd.getDeploymentId() = d778e129-cf3e-11ef-8c0e-aae291037f7a
    // pd.getId() = demo-flow1:2:d7bca0ec-cf3e-11ef-8c0e-aae291037f7a
    // pd.getKey() = demo-flow1
    // 由于这个流程进入以后是候选人流程， 所以这里需要对候选人的表达式进行赋值
    @Test
    void startProcessByKey() {
        Map<String, Object> flowVariables = new HashMap<>();
        flowVariables.put("candidate1", "lisi");
        flowVariables.put("candidate2", "zhangsan");
        flowVariables.put("candidate3", "wangwu");
        // 启动流程
        ProcessInstance processInstance = runtimeService.startProcessInstanceById("demo_flow2:2:95cdd37b-cf67-11ef-a431-4c496c811f92", flowVariables);
//        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("demoFlow1");
        System.out.println("processInstance: "+ processInstance);
    }

    // 经过上述步骤后，ACT_RU_TASK 表中会多一条数据 其 assignee=是null id=c410851c-cf68-11ef-8f60-4c496c811f92
    // 同时因为上面的 flowVariables 是流程实例的全局变量， 也一定会在 ACT_RU_VARIABLE 存有三条数据
    // 但是重要的是 ACT_RU_IDENTITYLINK 表。看type=candidate and task_id=c410851c-cf68-11ef-8f60-4c496c811f92 对应的三条数据，
    // 的user_id 字段分别是zhangsan、lisi、wangwu
    // 但是此时我们根据候选人查询 三个人的代办是没有任何结果的
    @Test
    void queryTask1() {
        // 查询任务
        List<org.flowable.task.api.Task> tasks = taskService.createTaskQuery()
                // 写多遍没用， 他只会查询一个 也就是最后一个
                .taskAssignee("zhangsan")
//                .taskAssignee("lisi")
//                .taskAssignee("wangwu")
                .list();
        if (CollectionUtils.isEmpty(tasks)) {
            System.err.println("tasks 查询结果为空");
        } else {
            tasks.forEach(task -> {
                System.out.println("task.getId() = " + task.getId());
                System.out.println("task.getName() = " + task.getName());
                System.out.println("task.getAssignee() = "+ task.getAssignee());
            });
        }
    }

    // 这时的查询要用候选人的api来查询任务信息
    @Test
    void queryTask2() {
        // 查询任务
        List<org.flowable.task.api.Task> tasks = taskService.createTaskQuery()
                .taskCandidateUser("wangwu")
                .list();
        if (CollectionUtils.isEmpty(tasks)) {
            System.err.println("tasks 查询结果为空");
        } else {
            tasks.forEach(task -> {
                System.out.println("task.getId() = " + task.getId());
                System.out.println("task.getName() = " + task.getName());
                System.out.println("task.getAssignee() = "+ task.getAssignee());
            });
        }
    }
    // 此时查询到了一条代办 具有任务id ， 但是任务人员是null
    //查询结果如下
    // task.getId() = c410851c-cf68-11ef-8f60-4c496c811f92
    // task.getName() = 候选人
    // task.getAssignee() = null
    // 其实就是箱单与 王五登录到了系统， 他有了一条代办， 但是这个任务的执行人还不是他，
    // 同样的 张三和李四如果登录到系统也是能查询到同样的一条信息的

    // 那么我们假设现在是王五登录到了系统， 拾取了任务， 那么任务就是王五的任务了
    @Test
    void claimTask() {
        // 拾取任务
        taskService.claim("c410851c-cf68-11ef-8f60-4c496c811f92", "wangwu");
    }
    //现在在看ACT_RU_TASK 对应的任务 assignee 就是wangwu
    // 这时再用候选人 的api 查询任务， 就查询不到了， 及时是wangwu 的user_id
    @Test
    void queryTask3() {
        // 查询任务
        List<org.flowable.task.api.Task> tasks = taskService.createTaskQuery()
                .taskCandidateUser("wangwu")
                .list();
        if (CollectionUtils.isEmpty(tasks)) {
            System.err.println("tasks 查询结果为空");
        } else {
            tasks.forEach(task -> {
                System.out.println("task.getId() = " + task.getId());
                System.out.println("task.getName() = " + task.getName());
                System.out.println("task.getAssignee() = "+ task.getAssignee());
            });
        }
    }

    // 现在应该用 assignee 的api 查询任务信息
    // 用wangwu 来查询能查到， 但是zhangsan、lisi 是不能查到信息的
    @Test
    void queryTask4() {
        // 查询任务
        List<org.flowable.task.api.Task> tasks = taskService.createTaskQuery()
                // 写多遍没用， 他只会查询一个 也就是最后一个
//                .taskAssignee("zhangsan")
//                .taskAssignee("lisi")
                .taskAssignee("wangwu")
                .list();
        if (CollectionUtils.isEmpty(tasks)) {
            System.err.println("tasks 查询结果为空");
        } else {
            tasks.forEach(task -> {
                System.out.println("task.getId() = " + task.getId());
                System.out.println("task.getName() = " + task.getName());
                System.out.println("task.getAssignee() = "+ task.getAssignee());
            });
        }
    }

    // 王五也可以归还 这个任务也就是调用unclaim 这里就不进行演示了， 执行后， 再查询就要用候选人api来查询了
//    @Test
//    void unclaimTask() {
//        // 还原任务
//        taskService.unclaim("c410851c-cf68-11ef-8f60-4c496c811f92");
//    }

    // 王五如果觉得他办不了， 他可以转任务指给 ange， 结果就是现在任务的 代办人是 ange
    @Test
    void setAssigneeTask() {
        // 转办任务
        taskService.setAssignee("c410851c-cf68-11ef-8f60-4c496c811f92", "ange");
    }

    // 这时 ange 上线可以查询任务
    @Test
    void queryTask5() {
        // 查询任务
        List<org.flowable.task.api.Task> tasks = taskService.createTaskQuery()
                .taskAssignee("ange")
                .list();
        if (CollectionUtils.isEmpty(tasks)) {
            System.err.println("tasks 查询结果为空");
        } else {
            tasks.forEach(task -> {
                System.out.println("task.getId() = " + task.getId());
                System.out.println("task.getName() = " + task.getName());
                System.out.println("task.getAssignee() = " + task.getAssignee());

            });
        }
    }

    // 之后ange完成任务 c410851c-cf68-11ef-8f60-4c496c811f92
    @Test
    void completeTask1() {
        // 完成任务
        taskService.complete("c410851c-cf68-11ef-8f60-4c496c811f92");
    }

    // 现在发生了一点变化， 当ange完成任务后， 进入下一个流程， 也就是用户组 指派
    // 这时ACT_RU_TASK 表中， 有一条记录， id=004698fd-cf73-11ef-98b7-4c496c811f92
    // 同时ACT_RU_IDENTITYLINK 表中， 有一条记录， task_id=004698fd-cf73-11ef-98b7-4c496c811f92 的记录
    // type=candidate group_id=candidateGroup 也就是直接赋值上的组名称
    // 现在使用 候选组查询的api 来查询代办任务
    @Test
    void queryTask6() {
        // 实际开发时， 是根据当前登录用户 获取部门或者用户组的api 获取到用户的组， 再传递到下面的参数
        // 查询任务
        List<org.flowable.task.api.Task> tasks = taskService.createTaskQuery()
                .taskCandidateGroup("candidateGroup")
                .list();
        if (CollectionUtils.isEmpty(tasks)) {
            System.err.println("tasks 查询结果为空");
        } else {
            tasks.forEach(task -> {
                System.out.println("task.getId() = " + task.getId());
            });
        }
    }
    // 查询结果  task.getId() = 004698fd-cf73-11ef-98b7-4c496c811f92
    // 现在假设 lige 登录到系统， 拾取了任务， 也就是 claim 了任务
    @Test
    void claimTask1() {
        // 拾取任务
        taskService.claim("004698fd-cf73-11ef-98b7-4c496c811f92", "lige");
    }
    //  004698fd-cf73-11ef-98b7-4c496c811f92 的这条任务就有了代办人 lige
    // 让lige完成任务
    @Test
    void completeTask2() {
        // 完成任务
        taskService.complete("004698fd-cf73-11ef-98b7-4c496c811f92");
    }
    // 现在已经完成了流程， 可以查询流程实例了
    @Test
    void queryProcessInstance() {
        // 查询流程实例
        List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery()
                .processInstanceId("c410851c-cf68-11ef-8f60-4c496c811f92")
                .list();
        if (CollectionUtils.isEmpty(processInstances)) {
            System.err.println("processInstances 查询结果为空");
        } else {
            processInstances.forEach(p -> {
                System.out.println("p.getId() = " + p.getId());
            });
        }
    }


}
